import time
import threading
import sys
from cushy_serial import CushySerial
from BrainLinkParser import BrainLinkParser
import pygame
import numpy as np

# ============== 配置 ==============
COM_PORT = "COM6"

running = threading.Event()
running.set()

pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512)

# 小星星旋律音符序列 (C大调简单版)
melody_notes = [523, 523, 659, 659, 698, 698, 659,    # Twinkle twinkle little star
                587, 587, 523, 523, 493, 493, 440,    # How I wonder what you are
                523, 523, 659, 659, 698, 698, 659,    # Up above the world so high
                587, 587, 523, 523, 493, 493, 440]    # Like a diamond in the sky

melody_index = 0
base_freq = 440.0
current_freq = 440.0
current_volume = 0.5

def play_smooth_note(freq, volume, duration=0.15):
    sample_rate = 44100
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    wave = np.sin(2 * np.pi * freq * t)
    wave += 0.25 * np.sin(2 * np.pi * freq * 2 * t)   # 轻微谐波，更像钢琴
    envelope = np.exp(-2.8 * t)
    audio = (wave * envelope * volume * 22000).astype(np.int16)
    stereo = np.column_stack((audio, audio))
    sound = pygame.sndarray.make_sound(stereo)
    sound.play()

# ============== EEG 回调（放大变化 + 旋律版） ==============
def on_eeg(data):
    global melody_index, current_freq, current_volume, base_freq

    attention = getattr(data, 'attention', 0)
    meditation = getattr(data, 'meditation', 0)
    blink = getattr(data, 'blinkStrength', getattr(data, 'blink', 0))

    print(f"专注度: {attention:3d} | 放松度: {meditation:3d} | 眨眼: {blink:3d}")
    sys.stdout.flush()

    # 放大变化：即使小变化也明显影响音乐
    attention_boost = (attention - 50) * 1.8      # 放大专注力影响
    meditation_boost = (meditation - 45) * 1.6    # 放大放松度影响

    # 计算基础频率（专注高→高音，放松高→低音）
    base_freq = 400 + attention_boost * 3.5 - meditation_boost * 2.5
    base_freq = max(280, min(880, base_freq))     # 限制范围，避免太尖或太低

    # 从小星星旋律中取音符，并根据脑波偏移
    note = melody_notes[melody_index % len(melody_notes)]
    target_freq = note + (attention_boost * 1.2) - (meditation_boost * 0.8)

    # 平滑过渡
    current_freq = current_freq * 0.78 + target_freq * 0.22
    current_volume = 0.45 + (attention_boost * 0.008) + (meditation_boost * 0.006)
    current_volume = max(0.35, min(0.95, current_volume))

    # 播放当前音符
    play_smooth_note(current_freq, current_volume, duration=0.18)

    # 推进旋律（让音乐更有歌的感觉）
    melody_index += 1
    if melody_index % 7 == 0:   # 每隔几拍换一个明显旋律点
        melody_index += 2

    # 眨眼加强高音和弦
    if blink > 60:
        play_smooth_note(current_freq + 120, current_volume + 0.25, 0.12)  # 高八度强调

# 其他回调
def on_extend_eeg(data): pass
def on_gyro(x, y, z): pass
def on_rr(rr1, rr2, rr3): pass
def on_raw(raw): pass

parser = BrainLinkParser(on_eeg, on_extend_eeg, on_gyro, on_rr, on_raw)

# ============== 串口线程 ==============
def start_brainlink():
    serial = None
    try:
        serial = CushySerial(COM_PORT, 115200)
        print(f"✅ 串口 {COM_PORT} 打开成功！")

        @serial.on_message()
        def handle_message(msg: bytes):
            if msg and running.is_set():
                parser.parse(msg)

        print("🎹 Brainlink Pro 脑波钢琴已启动！（小星星连贯版）")
        print("   专注度变化 → 旋律向上明亮    放松度变化 → 柔和低音    眨眼 → 加强高音\n")

        # 测试旋律
        print("播放《小星星》测试旋律...")
        for i in range(12):
            play_smooth_note(melody_notes[i % len(melody_notes)], 0.75, 0.25)
            time.sleep(0.28)
        print("测试结束，开始用意念演奏吧！\n")

        while running.is_set():
            time.sleep(0.05)

    except Exception as e:
        print(f"❌ 错误: {e}")
    finally:
        if serial:
            try:
                serial.close()
            except:
                pass

def graceful_shutdown():
    print("\n正在退出程序...")
    running.clear()
    time.sleep(0.6)
    pygame.mixer.quit()
    print("🎹 程序已安全退出")
    sys.stdout.flush()
    import os
    os._exit(0)

if __name__ == "__main__":
    thread = threading.Thread(target=start_brainlink, daemon=True)
    thread.start()

    print("程序运行中... 按 Ctrl + C 退出")

    try:
        while running.is_set():
            time.sleep(0.3)
    except KeyboardInterrupt:
        graceful_shutdown()
    except Exception:
        graceful_shutdown()